<?php
/**
 * CRMLite BootStrap Class
 *
 * @final
 * @package     Crmlite_App
 * @version     $Id: App.php 56 2007-09-10 02:01:01Z etng2004 $
 * @copyright   2006-2007 ETE.CN
 * @author      Yi BO  <etng2004@gmail.com>
 * @license     PHP Version 3.0 {@link http://www.php.net/license/3_0.txt}
 */
final class Crmlite_App
{
	/**
     * App Instance
     *
     * @static
     * @var Crmlite_App
     * @access private
     */
	private static $instance = null;
	/**
     * App Instance
     *
     * @static
     * @var Zend_Log
     * @access private
     */
	private static $logger = null;

	/**
     * Configuration
     *
     * @static
     * @var Zend_Config_Ini
     * @access private
     */
	private static $config = null;

	/**
     * Database connection
     *
     * @static
     * @var Zend_Db_Adapter
     * @access private
     */
	private static $db = null;

	/**
     * Cache
     *
     * @static
     * @var Zend_Cache_Core
     * @access private
     */
	private static $cache = null;

	/**
     * frontCtrl
     *
     * @var Zend_Controller_Front
     * @access private
     */
	private $frontCtrl = null;

	/**
     * __construct
     *
     * Mark as protected,You can not initial it outside of this class
     *
     * @access protected
     * @return void
     */
	protected function __construct()
	{
		define('REQUEST_TIME', isset($SERVER['REQUEST_TIME'])
		?$SERVER['REQUEST_TIME']
		:time());
	}
	/**
     * Impletion of Singelton Pattern
     *
     * @static
     * @access public
     * @return Crmlite_App
     */
	public static function getInstance()
	{
		$className = __CLASS__;
		if (!(self::$instance instanceof self))
		{
			self::$instance = new self();
			self::$instance->init();
		}
		return self::$instance;
	}

	protected function init()
	{
		$this->loadConfig();
		$this->setupLog();
		error_reporting(self::$config->error->reporting);
		ini_set('display_errors', self::$config->error->display_errors);
		//error_reporting(E_ALL|E_STRICT);
		//ini_set('display_errors', true);
		$this->setupCache();
		$this->setupDB();
		$this->setupSession();
		$this->setupAcl();
		$this->setupFrontCtrl();
		$this->setupViewRenderer();

		Inflector::setInflectionsFile(APP_DIR . '/Inflections.php');
	}


	/**
     *
     * 构造前端控制器
     *
     * @access public
     * @return Zend_Controller_Front
     */
	private function setupFrontCtrl()
	{
		$this->frontCtrl = self::$cache->load('frontCtrl');
		if (!$this->frontCtrl instanceof Zend_Controller_Front || self::$config->cache->rebuild)
		{
			$this->frontCtrl = Zend_Controller_Front::getInstance();
			$this->frontCtrl->throwExceptions(self::$config->frontController->throwExceptions);
			$this->frontCtrl->returnResponse(self::$config->frontController->returnResponse);
			$this->frontCtrl->setParam('useDefaultControllerAlways', self::$config->frontController->useDefaultControllerAlways);
			$this->frontCtrl->addModuleDirectory(APP_DIR . DIRECTORY_SEPARATOR . 'modules');
			self::$cache->save($this->frontCtrl, 'frontCtrl');
		}
		return $this->frontCtrl;
	}

	/**
     *
     * 构造试图渲染
     *
     * @access private
     * @return Zend_Controller_Action_Helper_ViewRenderer
     */
	private function setupViewRenderer()
	{
		$this->viewRenderer = self::$cache->load('viewRenderer');
		if (!$this->viewRenderer instanceof Zend_Controller_Action_Helper_ViewRenderer || self::$config->cache->rebuild)
		{
			$this->viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
			$this->viewRenderer->setViewSuffix(self::$config->view->suffix);
			$this->viewRenderer->setViewScriptPathSpec(self::$config->view->PathSpec);
			self::$cache->save($this->viewRenderer, 'viewRenderer');
		}
		Zend_Controller_Action_HelperBroker::addHelper($this->viewRenderer);
		// $options = array();
		// Crmlite_View_Helper_Pagination::addStyle('Basic', $options, false);
		// Crmlite_View_Helper_Pagination::addStyle('Advanced', $options, false);
		Crmlite_View_Helper_Pagination::setDefaultStyle('default');
		return $this->viewRenderer;
	}
	/**
     *
     * 构造数据库连接
     *
     * @access public
     * @return Zend_Db_Adapter
     */
	private function setupDB()
	{
		self::$db = Zend_Db::factory(self::$config->db->adapter, self::$config->db->config->toArray());
		self::$db->getProfiler()->setEnabled(self::$config->db->profiler);
		Zend_Db_Table_Abstract::setDefaultAdapter(self::$db);
		Zend_Db_Table_Abstract::setDefaultMetadataCache(self::$cache);
		self::$db->query('SET NAMES utf8');
		Zend_Registry::set('db', self::$db);
		$this->setupDbLog();
		return self::$db;
	}
	/**
     *
     * 加载配置文件
     *
     * @access public
     * @return Zend_Config_Ini
     */
	private function loadConfig()
	{
		self::$config = new Crmlite_Config_Ini(APP_DIR . DIRECTORY_SEPARATOR . 'config.ini', null);
		Zend_Registry::set('config', self::$config);
		// Set timezone
		date_default_timezone_set(self::$config->General->timezone);
		return self::$config;
	}
	/**
	 * 初始化系统缓存对象
	 *
	 * @return Zend_Cache
	 */
	private function setupCache()
	{
		$frontendOptions = self::$config->cache->frontend->toArray();
		$backendOptions = self::$config->cache->backend->toArray();
		$frontendName = $frontendOptions['name'];
		unset($frontendOptions['name']);
		$backendName = $backendOptions['name'];
		unset($backendOptions['name']);
		if (empty($backendOptions['cache_dir']))
		{
			$backendOptions['cache_dir'] = CACHE_DIR;
		}
		self::$cache = Zend_Cache::factory($frontendName, $backendName, $frontendOptions, $backendOptions);
		Zend_Registry::set('cache', self::$cache);
		return self::$cache;
	}
	/**
     *
     * 构造 session
     *
     * 这里不建议使用 Zend_Session::start ， 以在配置文件中添加 session.strict = false
     * 来保证自动调用 session.auto_start
     *
     * @access public
     * @return void
     */
	private function setupSession()
	{
		$sessionConfig = self::$config->session->toArray();
		if (empty($sessionConfig['save_path']))
		{
			$sessionConfig['save_path'] = SESSION_DIR;
		}
		Zend_Session::setOptions($sessionConfig);
		Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session());
		// Zend_Session::start();
	}

	/**
     *
     * 加载 ACL 机制
     *
     * 还未实现！！！
     *
     * @access private
     * @return Zend_Acl
     * @todo implement it
     */
	private function setupAcl()
	{
		$acl = self::$cache->load('acl');
		if (!$acl instanceof Zend_Acl || self::$config->cache->rebuild)
		{
			//$acl = Zend_Acl::build(self::$dbAdapter);
			$acl = new stdClass();
			self::$cache->save($acl, 'acl');
		}
		Zend_Registry::set('acl', $acl);
		return $acl;
	}
	/**
     *
     * 运行
     *
     * @access public
     * @return void
     */
	public function run()
	{
		if(!self::$config->frontController->returnResponse)
		{
			$this->frontCtrl->dispatch();
			return false;
		}
		$response = $this->frontCtrl->dispatch();
		//header('Content-Type: text/html; charset=utf-8');
		/* @var $response Zend_Controller_Response_Abstract*/
		$response->sendHeaders();
		$gzip_enabled = gzip_ob_start();
		$response->outputBody();
		if($gzip_enabled)
		{
		    ob_end_flush();
		}
	}
	private function setupLog()
	{
		self::$logger = new Zend_Log();
		if(self::$config->log->file->enable)
		{
			$file_writer = new Zend_Log_Writer_Stream(LOG_DIR . DIRECTORY_SEPARATOR . self::$config->log->file->name);
			self::$logger->addWriter($file_writer);
		}
		self::$logger->info('CRMLite started!');
	}
	private function setupDbLog()
	{
		if(self::$config->log->db->enable)
		{
			$columnMapping = array('level' => 'priority', 'message' => 'message');
			$db_writer = new Zend_Log_Writer_Db(self::$db, self::$config->log->db->table, $columnMapping);
			self::$logger->addWriter($db_writer);
		}
		self::$logger->info('DB logger setuped!');
	}
	public static function log($msg, $level = Zend_Log::DEBUG)
	{
		self::$logger->log($msg, $level);
	}
}